package com.jonniespratley.codegen.services
{
	import com.adobe.net.URI;
	import com.adobe.serialization.json.JSON;
	import com.adobe.serialization.json.JSONParseError;
	import com.jonniespratley.codegen.utils.CodeGenUtilities;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.utils.getTimer;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.utils.ObjectUtil;
	import mx.utils.URLUtil;

	//[Event (name="dynamicRequestResult", type="com.jonniespratley.codegen.services.DynamicRequestEvent" )]
	//[Event (name="dynamicRequestFault", type="com.jonniespratley.codegen.services.DynamicRequestEvent" )]

	public class DynamicRequestService extends EventDispatcher
	{
		static public const POST_REQUEST:String = 'post';
		static public const GET_REQUEST:String = 'get';
		[Bindable] static public var DUMP:String = '';

		[Bindable] static public var PHP_RAW_RESULT:String = '';
		[Bindable] static public var PHP_REQUEST_RESULT:Array = [];
		[Bindable] static public var PHP_REQUEST_RESULT_COLLECTION:ArrayCollection;

		[Bindable] static public var REQUEST_HEADERS:String = '';
		[Bindable] static public var REQUEST_ARGUMENTS:Array = [];
		[Bindable] static public var REQUEST_ARGUMENTS_FIELDS:Array = [];
		[Bindable] static public var REQUEST_PARAMETERS:ArrayCollection = new ArrayCollection();
		[Bindable] static public var REQUEST_BUILT_URL:String = '';

		[Bindable] static public var RESPONSE_RAW:String = '';
		[Bindable] static public var RESPONSE_HEADERS:String = '';
		[Bindable] static public var RESPONSE_COLLECTION:ArrayCollection = new ArrayCollection();
		[Bindable] static public var REQUEST_OBJECT:RequestVO = new RequestVO();
		[Bindable] public var requestObject:RequestVO;

		private var _requestSentTime:Number;
		private var _requestRecievedTime:Number;

		private var _requestSentSize:Number;
		private var _requestRecievedSize:Number;
		private var _requestParseTime:Number;
		private var _requestType:String;
		
		private var _requestMode:String;

		//Parse Timing
		private var _parseStartTime:Number;
		private var _parseEndTime:Number;
		private var _parseTotalTime:Number;

		//Request Timing
		private var _requestStartTime:Number;
		private var _requestEndTime:Number;
		private var _requestTotalTime:Number;

		//Total Timing
		private var _startTime:Number;
		private var _endTime:Number;
		private var _totalTime:Number;

		//Etc Timing

		//private var _url:String;
		private var _urlRequest:URLRequest;
		private var _urlLoader:URLLoader;

		public function DynamicRequestService()
		{
			super();
		}

		public function invokeMethod( url:String, method:String = 'get', mode:String = null, args:Array = null, resultFormat:String = 'json', resultHandler:Function = null ):void
		{
			//Start the Request TIme
			_requestStartTime = getTimer();
			resultFormat = 'json';
			//Build up a URI for name value pairs, from the URL parameter
			var uri:URI = new URI( url );
				uri.setQueryValue( 'm', mode ); //Mode on php side
				_requestMode = mode;

			//Create a new _urlRequest from the url we just build
			_urlRequest = new URLRequest();

			/*Check which type of request*/
			if ( method == DynamicRequestService.GET_REQUEST )
			{
				//GET method on the backend
				_urlRequest.method = URLRequestMethod.GET;

				//Now for the dynamic arguments lets loop though every name/value pair in the param and add it to the uri
				if ( args.length > -1 )
				{
						for ( var s:String in args )
						{
							uri.setQueryValue( s, args[s] );
						}


					//Get the arguments from the parameter
					var urlObject:Object = uri.getQueryByMap();

					for ( var str:String in urlObject )
					{
						//FOR EVERY PARAM NAME A OBJECT SETTING THE NAME AND VALUE INTO A OBJECT
						var nvArgs:Object = new Object();
							nvArgs.name = str;
							nvArgs.value = urlObject[ str ];

						//PUT THAT BITCH INTO THE REQUEST_COLLECTION FOR DISPLAY
						DynamicRequestService.REQUEST_PARAMETERS.addItem( nvArgs );
					}
				}
			} else if ( method == DynamicRequestService.POST_REQUEST )
			{

				//POST method on the backend
				_urlRequest.method = URLRequestMethod.POST;
				_urlRequest.data = args;
				//_urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			}




				//Create a new loader instance and register some event listeners
				_urlLoader = new URLLoader();
				_urlLoader.addEventListener( IOErrorEvent.IO_ERROR, onRequestIOError );
				_urlLoader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, onRequestSecurityError );
				_urlLoader.addEventListener( ProgressEvent.PROGRESS, onRequestProgress );
				_urlLoader.addEventListener( HTTPStatusEvent.HTTP_STATUS, onRequestStatus );

				//If its a post we need to add the params to the body of the request then post that shit.
				if ( resultHandler != null )
				{
					_urlLoader.addEventListener( Event.COMPLETE, resultHandler );
				} else {
					_urlLoader.addEventListener( Event.COMPLETE, onRequestComplete_json );
				}

			try
			{
				//Load up the request
				_urlRequest.url = uri.toString();
				_urlLoader.load( _urlRequest );

			} catch ( error:ArgumentError )
			{
				trace( 'Argument Error' );

			} catch ( error:SecurityError )
			{
				trace( 'Security Error' );
			}


			//============================================Finished

			//Set up the information for the history
			_requestType = _urlRequest.method;

			//Lets get the size of the sent request
			_requestSentSize = CodeGenUtilities.getUTF8Bytes( _urlRequest.url );

			//Set the complete url to the url we just build
			DynamicRequestService.REQUEST_BUILT_URL = _urlRequest.url;

			//Piece together some headers for display
			DynamicRequestService.REQUEST_HEADERS += 'URL: ' + String( _urlRequest.url ) + '\n';
			DynamicRequestService.REQUEST_HEADERS += 'Host: ' + URLUtil.getServerName( _urlRequest.url ) + '\n';
			DynamicRequestService.REQUEST_HEADERS += 'Method: ' + String( _urlRequest.method ) + ' ' + '\n';
			DynamicRequestService.REQUEST_HEADERS += 'Content Type: ' + String( _urlRequest.contentType ) + '\n';
			DynamicRequestService.REQUEST_HEADERS += 'Headers: ' + ObjectUtil.toString( _urlRequest.requestHeaders ) + '\n'

			//Get the sent time
			_requestSentTime = getTimer();
		}


		public function callClassFunction( baseurl:String, classLocation:String, classMethod:String, classMethodArgs:Array = null ):void
		{
			_requestStartTime  = getTimer();

			var mode:String = 'callClassFunction';
			var url:String = baseurl;
				/* _class: classPath,
				_func: classFunction,
				_args: classArgs.toString() */

			var args:Array = [];
				args['_class'] = classLocation;
				args['_func'] = classMethod;
				if ( classMethodArgs != null )
				{
					args['_args'] = classMethodArgs.toString();
				}

			invokeMethod( url,'get', mode, args, 'json', onRequestComplete_dynamic );
		}




		/**
		 * I handle the result from the request.
		 * @param event
		 *
		 */
		private function onRequestComplete_json( event:Event ):void
		{
			//End the request time
			_requestEndTime = getTimer();

			//Get the recieved time
			_requestRecievedTime = getTimer();

			var startEncodeTime:Number;
			var endEncodeTime:Number;

			//Start to parse the data if its a string
			if ( event.currentTarget.data is String )
			{
				//Get the start of encoding the json string
				startEncodeTime = getTimer();

				//Start the Parsing Time
				_parseStartTime = getTimer();

				var rawData:String = String( event.currentTarget.data );
				var jsonArray:Array = ( JSON.decode( rawData ) as Array );

				DynamicRequestService.PHP_RAW_RESULT = String( event.currentTarget.data );
				DynamicRequestService.PHP_REQUEST_RESULT = jsonArray;
				DynamicRequestService.PHP_REQUEST_RESULT_COLLECTION =  new ArrayCollection( jsonArray );

				/* ===========================================================================================
				 * Start the Timing of the results
				 * ===========================================================================================*/

				//End the parsing time
				_parseEndTime  = getTimer();

				//Get the end of the json parse
				endEncodeTime = getTimer();

				//Set the total encoded time which is end - start
				_requestParseTime = ( endEncodeTime - startEncodeTime );
				_requestRecievedSize = _urlLoader.bytesTotal;
				_requestTotalTime = ( _requestRecievedTime - _requestSentTime + _requestParseTime );


				/* ===========================================================================================
				 *  Add the request to the request history collection for recording
				 * ===========================================================================================*/

				//Add the request to the history collection
				var _request:RequestVO = new RequestVO();
					_request.newRequest(
										'HTTP',
										_requestType,
										_requestMode,
										_requestSentTime,
										_requestSentSize,
										_requestRecievedTime,
										_requestRecievedSize,
										_requestParseTime,
										_requestTotalTime,
										new ArrayCollection( jsonArray ),
										rawData );

				DynamicRequestService.REQUEST_OBJECT.addRequest( _request );

				/* ===========================================================================================
				 * Dispatch the event with the data
				 * ===========================================================================================*/

				dispatchEvent( new DynamicRequestEvent( DynamicRequestEvent.DYNAMIC_RESULT_EVENT, jsonArray ) );
			}

			//End the timer
			_endTime = getTimer();

			//Request Time
			_requestTotalTime = _requestEndTime - _requestStartTime;

			//Parse Time
			_parseTotalTime = _parseEndTime - _parseStartTime;

			//Total Time
			_totalTime = _endTime - _startTime;


			//Trace it
			DynamicRequestService.DUMP += '\nRequest Total Time: ' + _requestTotalTime +
					'\nParse Total Time: ' + _parseTotalTime +
					'\nTotal Time: ' + _totalTime +
					'\nStart Time: ' + _startTime +
					'\nEnd Time: ' + _endTime +
					'\nRequest Start Time: ' + _requestStartTime +
					'\nRequest End Time: ' + _requestEndTime +
					'\nParse Start Time: ' + _parseStartTime +
					'\nParse End Time:' + _parseEndTime;

		}

		private function onRequestComplete_dynamic( event:Event ):void
		{
			_requestEndTime = getTimer();


			//Get the recieved time
			_requestRecievedTime = getTimer();

			var startEncodeTime:Number;
			var endEncodeTime:Number;

			//Start to parse the data if its a string
			if ( event.currentTarget.data is String )
			{
				//Get the start of encoding the json string
				startEncodeTime = getTimer();

				//Start the Parsing Time
				_parseStartTime = getTimer();
				try {

					var rawData:String = String( event.currentTarget.data );
					var jsonArray:Array = ( JSON.decode( rawData ) as Array );

					DynamicRequestService.PHP_RAW_RESULT = String( event.currentTarget.data );
					DynamicRequestService.PHP_REQUEST_RESULT = jsonArray;
					DynamicRequestService.PHP_REQUEST_RESULT_COLLECTION =  new ArrayCollection( jsonArray );

					/* ===========================================================================================
					 * Start the Timing of the results
					 * ===========================================================================================*/

					//End the parsing time
					_parseEndTime  = getTimer();

					//Get the end of the json parse
					endEncodeTime = getTimer();

					//Set the total encoded time which is end - start
					_requestParseTime = endEncodeTime - startEncodeTime;
					_requestRecievedSize = _urlLoader.bytesTotal;
					//_requestTotalTime = _requestRecievedTime - _requestSentTime + _requestParseTime;


					/* ===========================================================================================
					 *  Add the request to the request history collection for recording
					 * ===========================================================================================*/

					//Add the request to the history collection
					var _request:RequestVO = new RequestVO();
						_request.newRequest(
											'HTTP',
											_requestType,
											_requestMode,
											_requestSentTime,
											_requestSentSize,
											_requestRecievedTime,
											_requestRecievedSize,
											_requestParseTime,
											_requestTotalTime,
											new ArrayCollection( jsonArray ),
											rawData );

					DynamicRequestService.REQUEST_OBJECT.addRequest( _request );

					/* ===========================================================================================
					 * Dispatch the event with the data
					 * ===========================================================================================*/

					dispatchEvent( new DynamicRequestEvent( DynamicRequestEvent.DYNAMIC_RESULT_EVENT, jsonArray ) );

				} catch ( e:JSONParseError ) {
				  trace(e.errorID, e.name, e.message, e.text );
				  trace(e.errorID, e.name, e.message, e.text );
				}

			}

			//End the timer
			_endTime = getTimer();

			//Request Time
			_requestTotalTime = _requestEndTime - _requestStartTime;

			//Parse Time
			_parseTotalTime = _parseEndTime - _parseStartTime;

			//Total Time
			_totalTime = _endTime - _startTime;


			//Trace it
			DynamicRequestService.DUMP += '\nRequest Total Time: ' + _requestTotalTime +
					'\nParse Total Time: ' + _parseTotalTime +
					'\nTotal Time: ' + _totalTime +
					'\nStart Time: ' + _startTime +
					'\nEnd Time: ' + _endTime +
					'\nRequest Start Time: ' + _requestStartTime +
					'\nRequest End Time: ' + _requestEndTime +
					'\nParse Start Time: ' + _parseStartTime +
					'\nParse End Time:' + _parseEndTime;


		}

		public function onRequestComplete( event:Event ):void
		{
			_endTime  = getTimer();
			_requestEndTime = getTimer();

			DynamicRequestService.PHP_RAW_RESULT = String( event.currentTarget.data );
			//Alert.show( ObjectUtil.toString( event.currentTarget.data ) );
		}

		private function onRequestSecurityError( event:SecurityErrorEvent ):void
		{
			trace('On Fault');
		}

		private function onRequestIOError( event:IOErrorEvent ):void
		{
			trace('On Fault');
		}

		private function onRequestStatus( event:HTTPStatusEvent ):void
		{
			DynamicRequestService.RESPONSE_HEADERS += 'HTTPStatus: ' + event.status;
		}

		private function onRequestProgress( event:ProgressEvent ):void
		{
			DynamicRequestService.RESPONSE_HEADERS += 'Data Loaded: ' + event.bytesLoaded;
			DynamicRequestService.RESPONSE_HEADERS += 'Data Total: ' +  event.bytesTotal;

			trace( 'Bytes Loaded: ' + event.bytesLoaded + '\n' + 'Bytes Total: ' + event.bytesTotal );
		}

	}
}